#include <iostream>
#include <string>
#include <unistd.h>
#include <vector>
#include <sys/types.h>
#include <sys/wait.h>
#include "Task.hpp"

// void work(int rfd)
// {
//     while (true)
//     {
//         int command=0;
//         int n= read(0,&command,sizeof(command));
//         if(n==sizeof(command))
//         {
//             std::cout << "pid:" << getpid() << std::endl;
//             ExcuteTask(command);
//         }
//         else if(n==0)
//         {
//             std::cout << "process pid:" << getpid() << "quit" << std::endl;
//         }
//     }
// }

// 信道封装为channel
class channel
{
public:
    channel(int wfd, pid_t id, const std::string &name)
        : _wfd(wfd), _subprocessid(id), _name(name)
    {
    }
    int Getwfd() { return _wfd; }
    pid_t GetProcessId() { return _subprocessid; }
    std::string GetName() { return _name; }
    void CloseChannel()
    {
        close(_wfd);
    }
    void Wait()
    {
        pid_t rid = waitpid(_subprocessid, nullptr, 0);
        if (rid > 0) // 等待成功
        {
            std::cout << "wait " << rid << "success" << std::endl;
        }
    }
    ~channel()
    {
    }

private:
    int _wfd;
    pid_t _subprocessid;
    std::string _name;
};

// 形参类型和命名规范
// const &: 输出
// & : 输入输出型参数
// * : 输出型参数
//  task_t task: 回调函数 通过下面回调方法直接调用函数；
void CreateChannelAndSub(int num, std::vector<channel> *channels, task_t task)
{
    for (int i = 0; i < num; i++)
    {

        int pipefd[2] = {0};
        int n = pipe(pipefd);
        if (n < 0)
            exit(1);
        // 2.创建子进程
        pid_t id = fork();
        if (id == 0)
        {
            // child - read
            // close(pipefd[1]);
            // work(pipefd[0]);
            // close(pipefd[0]);
            // exit(0);
            if (!channels->empty())
            {
                // 第二次后开始创建新的管道 假如现在是第八个子进程，channels存的就是前七个的写端,这里判断非空后就把他们全部关掉。
                for (auto &channel : *channels)
                    channel.CloseChannel();
            }
            // child - read
            close(pipefd[1]);
            dup2(pipefd[0], 0);
            task();
            close(pipefd[0]);
            exit(0);
        }
        // 3.创建一个channel名称
        std::string channel_name = "Channel-" + std::to_string(i);
        // 父进程 - write
        close(pipefd[0]);
        // a. 关闭所有的写端 b. 回收子进程
        channels->push_back(channel(pipefd[1], id, channel_name));
    }
}
// chan
int NextChannel(int channelnum)
{
    static int i = 0;
    int channel = i;
    i++;
    i %= channelnum;
    return channel;
}

void SendTaskCommand(channel &channel, int taskcommand)
{
    write(channel.Getwfd(), &taskcommand, sizeof(taskcommand));
}

void ctrlProcssOnce(std::vector<channel> &channels)
{

    sleep(1);
    // a.选择一个任务
    int taskcommand = SelectTask();
    // b.选择一个信道和进程
    int channel_index = NextChannel(channels.size());
    // c.发送任务
    SendTaskCommand(channels[channel_index], taskcommand);
    std::cout << std::endl;
    std::cout << "taskcommand: " << taskcommand << " channel: "
              << channels[channel_index].GetName() << " sub process: " << channels[channel_index].GetProcessId() << std::endl;
}
void ctrlProcess(std::vector<channel> &channels, int times = -1) // time为任务执行次数，如果大于0，那么执行times次；否则就无限循环。
{
    if (times > 0)
    {
        while (times--)
        {
            ctrlProcssOnce(channels);
        }
    }
    else
    {
        while (true)
        {
            ctrlProcssOnce(channels);
        }
    }
}

void CleanUpChannel(std::vector<channel> &channels)
{
    for (auto &channel : channels)
    {
        channel.CloseChannel();
    }
    for (auto &channel : channels)
    {
        usleep(1000000);
        channel.Wait();
    }
    // for (auto &channel : channels)
    // {
        
    //     channel.CloseChannel();
    //     channel.Wait();
    // }
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cerr << "Usage:" << argv[0] << "processnum" << std::endl;
        return 1;
    }
    int num = std::stoi(argv[1]);
    LoadTask();
    std::vector<channel> channels;

    // 1.创建信道和子进程
    CreateChannelAndSub(num, &channels, work1); //work1回调方法。

    // 2.通过channel控制子进程
    ctrlProcess(channels, 5);

    // 3.回收管道和子进程 a.关闭写端 b.回收子进程
    CleanUpChannel(channels);

    //sleep(100); 测试僵尸进程
    return 0;
}
